/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package fuzzy;

/**
 *
 * @author Nathy
 */
public class Fuzzificacao {

    //********************************************************************
    //VARIAVEIS

    /*0 - PERTO
    1 - MEDIO
    2 - LONGE*/
    double[] inferenciaSonar = new double[3];
    double[] inferenciaInfra = new double[3];
    int[][] regras = new int[3][3];
    //Armazena as regras baixo, medio e alto ativas
    double[] regrasBaixoAtivo = {0, 0, 0};
    double[] regrasMedioAtivo = {0, 0};
    double regrasAltoAtivo = 0;
    int numRegrasBaixoAtivo = 0;
    int numRegrasMedioAtivo = 0;
    int numRegrasAltoAtivo = 0;
    Trapezio trap = new Trapezio();
    double[] maxRegras = new double[3];
    // END VARIAVEIS
    //********************************************************************

    public void imprimeProcedimento(){
        System.out.println("InferenciaSonar:\n" +
        "Conjunto 1 "+ inferenciaSonar[0] );
        System.out.println("Conjunto 2 "+ inferenciaSonar[1]);
        System.out.println("Conjunto 3 "+ inferenciaSonar[2]);

        System.out.println("InferenciaInfra: \n" +
        "Conjunto 1 "+ inferenciaInfra[0] );
        System.out.println("Conjunto 2 "+ inferenciaInfra[1]);
        System.out.println("Conjunto 3 "+ inferenciaInfra[2]);

        System.out.println("Inferencia para Regras ativas:");
        for(int cont = 0; cont< this.numRegrasBaixoAtivo; cont++){
            System.out.println("O menor valor de inferencia para baixo eh"+ this.regrasBaixoAtivo[cont]);
            if(cont<this.numRegrasMedioAtivo)
                System.out.println("o menor valor de inferencia para medio eh"+ this.regrasMedioAtivo[cont]);
            if(cont< this.numRegrasAltoAtivo )
                System.out.println("o menor valor de inferencia para  alto eh"+ this.regrasAltoAtivo);
        }

        System.out.println("Agregacao:");
        for(int cont = 0; cont<this.maxRegras.length; cont++){
            System.out.println("O valor maximo para a regra"+ cont+ "  eh:  "+ maxRegras[cont]);
        }


    }
//Processamento das etapas da fuzzificacao: inferencia e agregacao
    public double[] controladorFuzzy(double distanciaInfra, double distanciaSonar) {

        inferenciaSonar = getInferenciaSonar(distanciaSonar);
        inferenciaInfra = getInferenciaInfra(distanciaInfra);

        regras = new Regras().defineRegras();
        this.conjuntoAtivo(regras, inferenciaSonar, inferenciaInfra);

        return this.agregacao();
    }

    /* P.S.: como estar parado nao eh fuzzy, e 0 exige
    que o boneco pare, retiramos ele do conjunto perto*/
    public double[] getInferenciaInfra(double distanciaInfra) {
        double[] limitesInfeInfra = {3, 15, 30, 75, 100};
        return this.getInferenciaEntrada(distanciaInfra, limitesInfeInfra);
    }

    public double[] getInferenciaSonar(double distanciaSonar) {
        double[] limitesInfeSonar = {3, 30, 70, 150, 200};
        return this.getInferenciaEntrada(distanciaSonar, limitesInfeSonar);
    }

    //PEga o maior valor de pertinencia para cada regra ativa
    private double[] agregacao() {
   
        maxRegras[0] = Math.max(regrasBaixoAtivo[0], Math.max(regrasBaixoAtivo[1], regrasBaixoAtivo[2]));
        maxRegras[1] = Math.max(regrasMedioAtivo[0], regrasMedioAtivo[1]);
        maxRegras[2] = regrasAltoAtivo;

        return maxRegras;
    }

    //Levanta as regras ativas e atribui o menor valor de pertinëncia
    private void conjuntoAtivo(int[][] regras, double[] infSonar, double[] infInfra) {

        //  double[] result = null;


        int regraBaixo = 0;
        int regraMedio = 0;
        int regraAlto = 0;

        for (int cont = 0; cont < infInfra.length; cont++) {
            //Se for zero, nao teve inferencia
            if (infInfra[cont] != 0) {
                for (int cont2 = 0; cont2 < infSonar.length; cont2++) {
                    if (infSonar[cont2] != 0) {
                        //Se a relacao das entradas resultam em velocidade baixa
                        if (regras[cont][cont2] == 0) {
                            regrasBaixoAtivo[regraBaixo] = Math.min(infInfra[cont], infSonar[cont2]);
                            regraBaixo++;

                        } //Se a relacao das entradas resultam em velocidade media
                        else if (regras[cont][cont2] == 1) {
                            regrasMedioAtivo[regraMedio] = Math.min(infInfra[cont], infSonar[cont2]);
                            regraMedio++;
                        } //Se a relacao das entradas resultam em velocidade alta
                        else if (regras[cont][cont2] == 2) {
                            regrasAltoAtivo = Math.min(infInfra[cont], infSonar[cont2]);
                            regraAlto++;
                        }
                    }
                }
            }
        }
        this.numRegrasAltoAtivo = regraAlto;
        this.numRegrasBaixoAtivo = regraBaixo;
        this.numRegrasMedioAtivo = regraMedio;
        //  return result;
    }

    //Calcula o grau de pertinëncia da distancia nos conjuntos da entrada
    private double[] getInferenciaEntrada(double distancia, double[] limites) {
        double[] inferenciaConj = {0, 0, 0};
        /*Limites do conjunto perto. */
        if (distancia >= limites[0] && distancia <= limites[1]) {
            //Inferencia no conjunto perto eh 1
            inferenciaConj[0] = 1;
        } //Limites que intercedem conjunto perto e medio
        else if (distancia > limites[1] && distancia < limites[2]) {
            double inf = trap.funcaoTrapezioX(distancia, limites[1], limites[2]);
            inferenciaConj[0] = inf;
            inferenciaConj[1] = 1.0 - inf;
        } //Conjunto medio
        else if (distancia >= limites[2] && distancia <= limites[3]) {
            inferenciaConj[1] = 1;
        } //Intercedem conjunto medio e longe
        else if (distancia > limites[3] && distancia < limites[4]) {
            double inf = trap.funcaoTrapezioX(distancia, limites[3], limites[4]);
            inferenciaConj[1] = inf;
            inferenciaConj[2] = 1.0 - inf;
        } //Conjunto longe
        else if (distancia >= limites[4]) {
            inferenciaConj[2] = 1.0;
        }
        return inferenciaConj;

    }

    //********************************************************************
    //GETS AND SETS
    public double getRegrasAltoAtivo() {
        return regrasAltoAtivo;
    }

    public double[] getRegrasBaixoAtivo() {
        return regrasBaixoAtivo;
    }

    public double[] getRegrasMedioAtivo() {
        return regrasMedioAtivo;
    }

    public int getNumRegrasAltoAtivo() {
        return numRegrasAltoAtivo;
    }

    public int getNumRegrasBaixoAtivo() {
        return numRegrasBaixoAtivo;
    }

    public int getNumRegrasMedioAtivo() {
        return numRegrasMedioAtivo;
    }
    //FIM GETS AND SETS
    //********************************************************************
}
